package com.hanxiaozhang.threadbase1ndedition.no9container.no4concurrentcontainer;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;

/**
 * 功能描述: <br>
 * 〈DelayQueue〉
 * <p>
 * 按紧迫程度排序，按时间进行调度任务
 * <p>
 * 无界的阻塞队列。
 * DelayQueue中的元素，必须继承Delayed类，重写compareTo、getDelay
 * <p>
 * 使用场景：
 * 淘宝订单业务：下单之后如果30min未支付就自动取消订单
 * 订餐通知：下单成功后60s给用户发短信通知
 * 关闭空闲连接：服务器中，有很多客户端连接，空闲一段时间之后需要关闭。
 * 缓存：缓存中的对象，超过空闲时间，从缓存中移除。
 * 任务超时处理。
 *
 * @Author:hanxinghua
 * @Date: 2021/11/21
 */
public class No11DelayQueue {

    private static DelayQueue<Task> tasks = new DelayQueue<>();

    public static void main(String[] args) throws InterruptedException {

        long now = System.currentTimeMillis();
        Task t1 = new Task("t1", now + 1000);
        Task t2 = new Task("t2", now + 2000);
        Task t3 = new Task("t3", now + 1500);
        Task t4 = new Task("t4", now + 2500);
        Task t5 = new Task("t5", now + 500);

        tasks.put(t1);
        tasks.put(t2);
        tasks.put(t3);
        tasks.put(t4);
        tasks.put(t5);

        System.out.println(tasks);

        for (int i = 0; i < 5; i++) {
            System.out.println(tasks.take());
        }
    }

    /**
     * DelayQueue中的元素，必须继承Delayed类，重写compareTo、getDelay
     */
    static class Task implements Delayed {

        private String name;
        private long runningTime;

        public Task(String name, long rt) {
            this.name = name;
            this.runningTime = rt;
        }

        /**
         * 比较到期时间
         *
         * @param o
         * @return
         */
        @Override
        public int compareTo(Delayed o) {
            if (this.getDelay(TimeUnit.MILLISECONDS) < o.getDelay(TimeUnit.MILLISECONDS)) {
                return -1;
            } else if (this.getDelay(TimeUnit.MILLISECONDS) > o.getDelay(TimeUnit.MILLISECONDS)) {
                return 1;
            } else {
                return 0;
            }

        }

        /**
         * 返回给定时间单位内与此对象关联的剩余延迟
         *
         * @param unit
         * @return
         */
        @Override
        public long getDelay(TimeUnit unit) {

            // convert(long sourceDuration, TimeUnit sourceUnit) 将时间转换给定格式
            return unit.convert(runningTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
        }

        @Override
        public String toString() {

            return name + " " + runningTime;
        }

    }

}
